using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Xml.XPath;
using TeamFoundationServerSensor;

public partial class SubscribeService : System.Web.UI.Page {

    // A class used for check, subscribing and unsubscribing events.
    Subscribe subservices;

    // A hashtable of IDs and the event types they are registered to.
    Hashtable hashy;

    /// <summary>
    /// Load some default settings.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void Page_Load(object sender, EventArgs e) {

        try {
            // Check the parameters are correct.
            string address = Settings.Instance.getSetting("Address");
            string server = Settings.Instance.getSetting("Server");
            subservices = new Subscribe(address, server);

            if (!this.Page.IsPostBack) {
                checkServices();
            }
        }
        catch (ArgumentException ex) {
            Logger.TheInstance.Log(ex);
            this.ServiceList.Enabled = false;
            this.SuperSubscribe.Enabled = false;
            this.UnsubscribeAll.Enabled = false;
            this.Refresh.Enabled = false;
            subservices = null;
            this.TextOutput.Text += "\nError: " + ex.Message;
        }
        catch (Exception ex) {
            Logger.TheInstance.Log(ex);
            this.ServiceList.Enabled = false;
            this.SuperSubscribe.Enabled = false;
            this.UnsubscribeAll.Enabled = false;
            this.Refresh.Enabled = false;
            this.TextOutput.Text += "\nError: " + ex.Message;
        }
    }

    /// <summary>
    /// Check the boxes of items that we are already subscribed to.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void checkServices(object sender, EventArgs e) {
        checkServices();
    }

    /// <summary>
    /// General method used to check whether the parameters for signing up for
    /// an event are correct.
    /// </summary>
    private void checkServices() {

        // Check that the subscription service exists.
        if (subservices == null) {
            return;
        }

        // Always recheck the subscriptions.
        hashy = subservices.getSubscriptions();

        // Check to make sure
        if (hashy.ContainsKey("error")) {
            throw new ArgumentOutOfRangeException("Could not retrieve a complete set of values from server.", new ArgumentException());
        }

        // Go through each checkbox and make sure that the service actually exists. 
        foreach (DataListItem eventtype in ServiceList.Items) {
            
            // Set the checkbox to the correct value based on subscription service
            HtmlInputCheckBox checkbox = (HtmlInputCheckBox)eventtype.FindControl("serviceCheckbox");
            checkbox.Checked = false;
            if (hashy.ContainsKey(checkbox.Value)) {
                checkbox.Checked = true;

                // Set the textbox filter expression to the correct value if set in 
                // subscription.
                TextBox filterTextbox = (TextBox)eventtype.FindControl("serviceFilter");
                filterTextbox.Text = ((EventSubscription)hashy[checkbox.Value]).Expression;
            }
        }
    }

    /// <summary>
    /// After a user changes an item this method gets called. We need to 
    /// subscribe events which are not in database and checked and unsubscribe 
    /// items which are in database but not checked.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void UpdateServices(object sender, EventArgs e) {

        // Check which items have changed from what is in the database.
        hashy = subservices.getSubscriptions();
        foreach (DataListItem eventtype in ServiceList.Items) {

            // Make sure to work on checkbox
            HtmlInputCheckBox checkbox = (HtmlInputCheckBox)eventtype.FindControl("serviceCheckbox");

            // Check event actually exists.
            if (!checkValidEvent(checkbox.Value)) {
                this.TextOutput.Text += "\nError: Event does not exist: " + checkbox.Value;
                break;
            }

            // User wants to subscribe to events but its not in the database.
            if (checkbox.Checked == true
                && !hashy.ContainsKey(checkbox.Value)) {
                
                // Load the xml file for reading.
                XmlDataDocument xmlDatadoc = new XmlDataDocument();
                xmlDatadoc.DataSet.ReadXml(Server.MapPath("Services.xml"));
                DataSet dataset = xmlDatadoc.DataSet;
                DataView xmldata = new DataView(dataset.Tables["Service"], "", 
                    "Type", DataViewRowState.CurrentRows);

                // Find the service with this type and extract its url.
                int index = xmldata.Find(checkbox.Value);

                // No URL or row exists.
                if (index == -1) {
                    this.TextOutput.Text += "\nError: URL does not exist: " + checkbox.Value;
                    break;
                }

                // Subscribe to service.
                else {
                    string URL = xmldata[index]["URL"].ToString();

                    // Determine if a filter is present
                    TextBox filterTextbox = (TextBox)eventtype.FindControl("serviceFilter");
                    string filterText = filterTextbox.Text.Trim();
                    
                    // The validator should already check that the xpath expression is correctly formatted.
                    int ID = subservices.subscribeService(checkbox.Value, URL, filterText);

                    // Check the returning ID.
                    if (0 < ID) {
                        this.TextOutput.Text += "\nSuccesfully subscribe: ID - " 
                            + ID + " " + checkbox.Value;
                    }
                }
            }

            // User does not want this event subscribed to but it is 
            // in the database.
            else if (checkbox.Checked == false
                && hashy.ContainsKey(checkbox.Value)) {

                // Anarchic way to determine which ID needs removing.
                IDictionaryEnumerator hashenum = hashy.GetEnumerator();
                while (hashenum.MoveNext()) {
                    EventSubscription temp = (EventSubscription)hashenum.Value;
                    if (checkbox.Value.Equals(temp.Type)) {
                        if (!subservices.removeService(temp.ID)) {
                            this.TextOutput.Text += "\nError: Could not unsubscribe event: " + checkbox.Value;
                        }
                        else {
                            this.TextOutput.Text += "\nSuccesfully unsubscribe: " + checkbox.Value;
                        }
                        break;
                    }
                }
            }
        }

        // Update everything.
        checkServices();
    }

    /// <summary>
    ///  Refresh the current list.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void RefreshClick(object sender, EventArgs e) {
        checkServices();
    }

    /// <summary>
    /// Double check to make sure the event can be subscribed. Simple hacker 
    /// protection and possibly extend to be deprecated event protection.
    /// </summary>
    /// <param name="serviceEvent"></param>
    /// <returns></returns>
    private Boolean checkValidEvent(string serviceEvent) {

        // Load the xml file for reading.
        XmlDataDocument xmlDatadoc = new XmlDataDocument();
        xmlDatadoc.DataSet.ReadXml(Server.MapPath("Services.xml"));
        DataSet dataset = xmlDatadoc.DataSet;
        DataView xmldata = new DataView(dataset.Tables["Service"], "",
            "Type", DataViewRowState.CurrentRows);

        // Find the if the event exists.
        int index = xmldata.Find(serviceEvent);

        // No event or row exists.
        if (index == -1) {
            this.TextOutput.Text += "\nError: Event does not exist: " + serviceEvent;
        }
        else {
            return true;
        }

        return false;
    }

    /// <summary>
    /// Subscribe to all events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void SuperSubscribeClick(object sender, EventArgs e) {

        // Select all events.
        foreach (DataListItem eventtype in ServiceList.Items) {

            // Make sure to work on checkbox
            HtmlInputCheckBox checkbox = (HtmlInputCheckBox)eventtype.FindControl("serviceCheckbox");

            checkbox.Checked = true;
        }

        // Subscribe to remaining events.
        UpdateServices(sender, e);
    }

    /// <summary>
    /// Unsubscribe all events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void UnsubscribeAllClick(object sender, EventArgs e) {

        // Select all events.
        foreach (DataListItem eventtype in ServiceList.Items) {

            // Make sure to work on checkbox
            HtmlInputCheckBox checkbox = (HtmlInputCheckBox)eventtype.FindControl("serviceCheckbox");

            checkbox.Checked = false;
        }

        // Subscribe to remaining events.
        UpdateServices(sender, e);
    }

    /// <summary>
    /// Checks to verfify that the XPath Query Filter in the textbox is correct.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e">The possible XPath query.</param>
    protected void XPathFilterValidate(object sender, ServerValidateEventArgs e) {

        // Check that the file exists and can be executed.
        try {
            XPathExpression checkExpression = XPathExpression.Compile(e.Value);
            e.IsValid = true;
        }
        catch (XPathException) {
            e.IsValid = false;
        }
    }
}
